package org.zjx.swing.view;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.zjx.entity.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.regex.Pattern;

public class SceneView extends JFrame {
    private static final Font TITLE_FONT = new Font("微软雅黑", Font.BOLD, 20);
    private static final Font LABEL_FONT = new Font("宋体", Font.PLAIN, 20);
    private static final float SCALE_FACTOR = 2.0f;

    private File currentFile;

    private JTabbedPane tabbedPane;
    private JTable sceneTable, npcTable, roomTable, wayPointTable;
    private DefaultTableModel sceneModel, npcModel, roomModel, wayPointModel;
    private JLabel statusLabel;

    private JButton openBtn, saveBtn, saveAsBtn, newSceneBtn, helpBtn, addNpcBtn, addBtn;
    private JButton addWayPointBtn;
    // 坐标验证正则表达式
    private static final Pattern COORDINATE_PATTERN = Pattern.compile("^\\d+\\s*,\\s*\\d+$");

    public SceneView() {
        initUI();
        setupTableRenderers();
        setLocationRelativeTo(null);

        // 添加按钮事件监听器
        addAddNpcButtonListener();
        addAddRoomButtonListener();
        addAddWayPointButtonListener();
        addHelpButtonListener(e -> showHelp());
        addOpenButtonListener(e -> {
            showOpen();
            // 打开文件时记录当前文件路径
            JFileChooser fileChooser = new JFileChooser();
            fileChooser.setFileFilter(new FileNameExtensionFilter("XML Files", "xml"));
            int result = fileChooser.showOpenDialog(this);
            if (result == JFileChooser.APPROVE_OPTION) {
                currentFile = fileChooser.getSelectedFile();
            }
        });
        addSaveButtonListener(e -> showSave());
        addSaveAsButtonListener(e -> showLin());
        addSceneButtonListener(e ->{});

        setVisible(true);
    }



    public void addSceneButtonListener(ActionListener listener) {
        newSceneBtn.addActionListener(e -> {
            // 检查场景表格是否已有数据
            if (sceneModel.getRowCount() > 0) {
                int result = JOptionPane.showConfirmDialog(
                        this,
                        "场景表格已有数据，是否覆盖创建新场景？",
                        "确认提示",
                        JOptionPane.YES_NO_OPTION
                );
                if (result == JOptionPane.NO_OPTION) {
                    return; // 用户选择不覆盖，直接返回
                }
            }

            // 自动生成相关数据到场景表格
            generateDefaultScene();
        });
    }

    private void generateDefaultScene() {
        sceneModel.setRowCount(0); // 清空现有数据
        // 假设的默认场景数据
        sceneModel.addRow(new Object[]{"名称", "新建场景"});
        sceneModel.addRow(new Object[]{"Tab键打开所在位置", "未知位置"});
        sceneModel.addRow(new Object[]{"大小", "1000, 800"});
        sceneModel.addRow(new Object[]{"是否遇怪", "否"});
    }

    private boolean isValidCoordinate(String input) {
        return COORDINATE_PATTERN.matcher(input.trim()).matches();
    }

    private void addAddNpcButtonListener() {
        addNpcBtn.addActionListener(e -> {
            JPanel panel = new JPanel(new GridLayout(0, 2));
            JTextField nameField = new JTextField();
            JTextField typeField = new JTextField();
            JTextArea coordArea = new JTextArea();
            JTextArea dialogueArea = new JTextArea();

            panel.add(new JLabel("名称:"));
            panel.add(nameField);
            panel.add(new JLabel("类型:"));
            panel.add(typeField);
            panel.add(new JLabel("坐标 (空格分隔，格式: x, y):"));
            panel.add(new JScrollPane(coordArea));
            panel.add(new JLabel("对话内容 (每行一条对话):"));
            panel.add(new JScrollPane(dialogueArea));

            // 创建自定义对话框
            JOptionPane optionPane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
            JDialog dialog = optionPane.createDialog(this, "添加 NPC");
            dialog.setSize(400, 300);
            dialog.setResizable(false); // 禁止调整大小

            // 添加确认按钮监听器
            optionPane.addPropertyChangeListener(event -> {
                if (dialog.isVisible() && event.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {
                    dialog.setVisible(false);
                }
            });

            dialog.setVisible(true);

            Integer result = (Integer) optionPane.getValue();
            if (result != null && result == JOptionPane.OK_OPTION) {
                String name = nameField.getText().trim();
                String type = typeField.getText().trim();
                String[] coordLines = coordArea.getText().split("\\s+");
                String[] dialogueLines = dialogueArea.getText().split("\\n");

                if (!name.isEmpty() && !type.isEmpty() && coordLines.length > 0 && dialogueLines.length > 0) {
                    boolean isValid = true;
                    List<Coordinate> coordinatesList = new ArrayList<>();

                    for (String coord : coordLines) {
                        if (!isValidCoordinate(coord)) {
                            showError("坐标格式错误");
                            isValid = false;
                            break;
                        }
                        String[] parts = coord.trim().split(",");
                        coordinatesList.add(new Coordinate(
                                Integer.parseInt(parts[0].trim()),
                                Integer.parseInt(parts[1].trim())
                        ));
                    }

                    if (isValid) {
                        StringBuilder dialogueBuilder = new StringBuilder();
                        for (String dialogue : dialogueLines) {
                            dialogueBuilder.append(dialogue.trim()).append("\n");
                        }
                        String dialogues = dialogueBuilder.toString().trim();

                        String coordinatesStr = coordinatesList.stream()
                                .map(coord -> coord.getX() + "," + coord.getY())
                                .collect(Collectors.joining(" "));
                        npcModel.addRow(new Object[]{name, type, coordinatesStr, dialogues});
                    }
                } else {
                    showError("请填写所有信息");
                }
            }
        });
    }

    private void addAddRoomButtonListener() {
        addBtn.addActionListener(e -> {
            JPanel panel = new JPanel(new GridLayout(0, 2));
            JTextField nameField = new JTextField();
            JTextField sizeField = new JTextField();
            JComboBox<Boolean> movableComboBox = new JComboBox<>(new Boolean[]{true, false});
            JTextField wayPointField = new JTextField();
            JTextField npcField = new JTextField();

            panel.add(new JLabel("名称:"));
            panel.add(nameField);
            panel.add(new JLabel("尺寸:"));
            panel.add(sizeField);
            panel.add(new JLabel("界面固定:"));
            panel.add(movableComboBox);
            panel.add(new JLabel("传送点:"));
            panel.add(wayPointField);
            panel.add(new JLabel("关联NPC:"));
            panel.add(npcField);

            // 创建自定义对话框
            JOptionPane optionPane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
            JDialog dialog = optionPane.createDialog(this, "添加房间");
            dialog.setSize(400, 300);
            dialog.setResizable(false); // 禁止调整大小

            // 添加确认按钮监听器
            optionPane.addPropertyChangeListener(event -> {
                if (dialog.isVisible() && event.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {
                    dialog.setVisible(false);
                }
            });

            dialog.setVisible(true);

            Integer result = (Integer) optionPane.getValue();
            if (result != null && result == JOptionPane.OK_OPTION) {
                String name = nameField.getText().trim();
                String size = sizeField.getText().trim();
                Boolean movable = (Boolean) movableComboBox.getSelectedItem();
                String wayPoints = wayPointField.getText().trim();
                String npcs = npcField.getText().trim();

                if (!name.isEmpty() && !size.isEmpty() && movable != null && !wayPoints.isEmpty() && !npcs.isEmpty()) {
                    if (!isValidCoordinate(size)) {
                        showError("尺寸格式错误");
                    } else {
                        roomModel.addRow(new Object[]{name, size, movable, wayPoints, npcs});
                    }
                } else {
                    showError("请填写所有信息");
                }
            }
        });
    }

    private void addAddWayPointButtonListener() {
        addWayPointBtn.addActionListener(e -> {
            JPanel panel = new JPanel(new GridLayout(0, 2));
            JTextField typeField = new JTextField();
            JTextField apertureCoordField = new JTextField();
            JTextField startCoordField = new JTextField();
            JTextField startCoordNoteField = new JTextField();
            JTextField endCoordField = new JTextField();
            JTextField endCoordNoteField = new JTextField();
            JTextField roomField = new JTextField();

            panel.add(new JLabel("传送点类型:"));
            panel.add(typeField);
            panel.add(new JLabel("光圈坐标(x,y):"));
            panel.add(apertureCoordField);
            panel.add(new JLabel("起始坐标(x,y):"));
            panel.add(startCoordField);
            panel.add(new JLabel("起始备注:"));
            panel.add(startCoordNoteField);
            panel.add(new JLabel("终点坐标(x,y):"));
            panel.add(endCoordField);
            panel.add(new JLabel("终点备注:"));
            panel.add(endCoordNoteField);
            panel.add(new JLabel("所属房间:"));
            panel.add(roomField);

            // 创建自定义对话框
            JOptionPane optionPane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
            JDialog dialog = optionPane.createDialog(this, "添加传送点");
            dialog.setSize(400, 300);
            dialog.setResizable(false); // 禁止调整大小

            // 添加确认按钮监听器
            optionPane.addPropertyChangeListener(event -> {
                if (dialog.isVisible() && event.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {
                    dialog.setVisible(false);
                }
            });

            dialog.setVisible(true);

            Integer result = (Integer) optionPane.getValue();
            if (result != null && result == JOptionPane.OK_OPTION) {
                String type = typeField.getText().trim();
                String apertureCoord = apertureCoordField.getText().trim();
                String startCoord = startCoordField.getText().trim();
                String startCoordNote = startCoordNoteField.getText().trim();
                String endCoord = endCoordField.getText().trim();
                String endCoordNote = endCoordNoteField.getText().trim();
                String room = roomField.getText().trim();

                if (!type.isEmpty() && !apertureCoord.isEmpty() && !startCoord.isEmpty() &&
                        !startCoordNote.isEmpty() && !endCoord.isEmpty() && !endCoordNote.isEmpty() &&
                        !room.isEmpty()) {
                    if (!isValidCoordinate(apertureCoord) || !isValidCoordinate(startCoord) || !isValidCoordinate(endCoord)) {
                        showError("坐标格式错误");
                    } else {
                        String combinedStart = startCoord + " (" + startCoordNote + ")";
                        String combinedEnd = endCoord + " (" + endCoordNote + ")";
                        wayPointModel.addRow(new Object[]{type, apertureCoord, combinedStart, combinedEnd, room});
                    }
                } else {
                    showError("请填写所有信息");
                }
            }
        });
    }

    private void initUI() {
        setTitle("场景编辑器");
        setSize(800, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout(10, 10));

        JToolBar toolBar = createToolBar();
        add(toolBar, BorderLayout.NORTH);

        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));

        tabbedPane = new JTabbedPane();
        tabbedPane.setFont(TITLE_FONT);

        sceneTable = createSceneTable();
        npcTable = createNpcTable();
        roomTable = createRoomTable();
        wayPointTable = createWayPointTable();

        addRightClickMenu(sceneTable);
        addRightClickMenu(npcTable);
        addRightClickMenu(roomTable);
        addRightClickMenu(wayPointTable);

        tabbedPane.addTab("场景属性", createTablePanel(sceneTable));
        tabbedPane.addTab("NPC管理", createTablePanel(npcTable));
        tabbedPane.addTab("房间管理", createTablePanel(roomTable));
        tabbedPane.addTab("传送点管理", createTablePanel(wayPointTable));

        mainPanel.add(tabbedPane, BorderLayout.CENTER);
        add(mainPanel);

        statusLabel = new JLabel("就绪");
        statusLabel.setBorder(new CompoundBorder(
                new MatteBorder(1, 0, 0, 0, Color.GRAY),
                new EmptyBorder(5, 10, 5, 10)
        ));
        add(statusLabel, BorderLayout.SOUTH);
    }

    private void addRightClickMenu(JTable table) {
        JPopupMenu popupMenu = new JPopupMenu();

        JMenuItem deleteMenuItem = new JMenuItem("删除");
        deleteMenuItem.addActionListener(e -> {
            int selectedRow = table.getSelectedRow();
            if (selectedRow != -1) {
                DefaultTableModel model = (DefaultTableModel) table.getModel();
                model.removeRow(selectedRow);
            }
        });
        popupMenu.add(deleteMenuItem);

        JMenuItem editMenuItem = new JMenuItem("编辑");
        editMenuItem.addActionListener(e -> {
            int selectedRow = table.getSelectedRow();
            if (selectedRow != -1) {
                editTableRow(table, selectedRow);
            }
        });
        popupMenu.add(editMenuItem);

        table.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                if (e.isPopupTrigger()) showPopupMenu(e);
            }
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) showPopupMenu(e);
            }
            private void showPopupMenu(MouseEvent e) {
                int row = table.rowAtPoint(e.getPoint());
                int col = table.columnAtPoint(e.getPoint());
                if (row >= 0 && col >= 0) {
                    table.setRowSelectionInterval(row, row);
                    table.setColumnSelectionInterval(col, col);
                    popupMenu.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });
    }

    private void editTableRow(JTable table, int selectedRow) {
        DefaultTableModel model = (DefaultTableModel) table.getModel();

        if (table == sceneTable) {
            editSceneRow(selectedRow);
        } else if (table == npcTable) {
            editNpcRow(selectedRow);
        } else if (table == roomTable) {
            editRoomRow(selectedRow);
        } else if (table == wayPointTable) {
            editWayPointRow(selectedRow);
        }
    }

    private void editSceneRow(int selectedRow) {
        JPanel panel = new JPanel(new GridLayout(0, 2));
        JTextField nameField = new JTextField((String) sceneModel.getValueAt(selectedRow, 1));
        JTextField sizeField = new JTextField();

        panel.add(new JLabel("名称:"));
        panel.add(nameField);
        panel.add(new JLabel("大小 (格式: x, y):"));
        panel.add(sizeField);

        int result = JOptionPane.showConfirmDialog(this, panel, "编辑场景属性", JOptionPane.OK_CANCEL_OPTION);
        if (result == JOptionPane.OK_OPTION) {
            String name = nameField.getText().trim();
            String size = sizeField.getText().trim();

            if (!name.isEmpty() && isValidCoordinate(size)) {
                sceneModel.setValueAt(name, selectedRow, 1);
            } else {
                showError("请输入有效名称和坐标");
            }
        }
    }

    private void editNpcRow(int selectedRow) {
        JPanel panel = new JPanel(new GridLayout(0, 2)); // 保持原有布局
        JTextField nameField = new JTextField((String) npcModel.getValueAt(selectedRow, 0));
        JTextField typeField = new JTextField((String) npcModel.getValueAt(selectedRow, 1));

        // 调整坐标和对话区域的尺寸
        JTextArea coordArea = new JTextArea((String) npcModel.getValueAt(selectedRow, 2));
        coordArea.setRows(5); // 增加行数
        coordArea.setColumns(20); // 增加列数

        JTextArea dialogueArea = new JTextArea((String) npcModel.getValueAt(selectedRow, 3));
        dialogueArea.setRows(8);
        dialogueArea.setColumns(30);

        // 初始化对话内容显示（保留原始格式）
        String rawDialogues = (String) npcModel.getValueAt(selectedRow, 3);
        String[] lines = rawDialogues.split("\n");
        StringBuilder displayDialogues = new StringBuilder();
        for (String line : lines) {
            if (line.startsWith("* ")) {
                displayDialogues.append(line.substring(2)).append("\n");
            } else {
                displayDialogues.append(line).append("\n");
            }
        }
        dialogueArea.setText(displayDialogues.toString().trim());

        // 添加带滚动条的面板容器
        panel.add(new JLabel("名称:"));
        panel.add(nameField);
        panel.add(new JLabel("类型:"));
        panel.add(typeField);
        panel.add(new JLabel("坐标 (空格分隔，格式: x, y):"));
        panel.add(new JScrollPane(coordArea)); // 添加滚动条
        panel.add(new JLabel("对话内容 (每行一条对话):"));
        panel.add(new JScrollPane(dialogueArea)); // 添加滚动条

        while (true) {
            int result = JOptionPane.showConfirmDialog(this, panel, "编辑NPC", JOptionPane.OK_CANCEL_OPTION);
            if (result != JOptionPane.OK_OPTION) break;

            String name = nameField.getText().trim();
            String type = typeField.getText().trim();
            String[] coordLines = coordArea.getText().split("\\s+");
            String[] dialogueLines = dialogueArea.getText().split("\\n");

            if (!name.isEmpty() && !type.isEmpty() && coordLines.length > 0 && dialogueLines.length > 0) {
                boolean isValid = true;
                List<Coordinate> coordinatesList = new ArrayList<>();

                // 坐标验证和解析
                for (String coord : coordLines) {
                    if (!isValidCoordinate(coord.trim())) {
                        showError("坐标格式错误");
                        isValid = false;
                        break;
                    }
                    String[] parts = coord.trim().split(",");
                    coordinatesList.add(new Coordinate(
                            Integer.parseInt(parts[0].trim()),
                            Integer.parseInt(parts[1].trim())
                    ));
                }

                if (isValid) {
                    // 对话内容处理（保留原始格式）
                    StringBuilder dialogueBuilder = new StringBuilder();
                    for (String dialogue : dialogueLines) {
                        dialogueBuilder.append("* ").append(dialogue.trim()).append("\n");
                    }
                    String dialogues = dialogueBuilder.toString().trim();

                    // 坐标格式化
                    String coordinatesStr = coordinatesList.stream()
                            .map(coord -> coord.getX() + "," + coord.getY())
                            .collect(Collectors.joining(" "));

                    // 更新表格数据
                    npcModel.setValueAt(name, selectedRow, 0);
                    npcModel.setValueAt(type, selectedRow, 1);
                    npcModel.setValueAt(coordinatesStr, selectedRow, 2);
                    npcModel.setValueAt(dialogues, selectedRow, 3);
                    break;
                }
            } else {
                showError("请填写所有信息");
            }
        }
    }

    private void editRoomRow(int selectedRow) {
        JPanel panel = new JPanel(new GridLayout(0, 2));
        JTextField nameField = new JTextField((String) roomModel.getValueAt(selectedRow, 0));
        JTextField sizeField = new JTextField((String) roomModel.getValueAt(selectedRow, 1));
        JComboBox<Boolean> movableCombo = new JComboBox<>(new Boolean[]{true, false});
        movableCombo.setSelectedItem((Boolean) roomModel.getValueAt(selectedRow, 2));
        JTextField wayPointField = new JTextField((String) roomModel.getValueAt(selectedRow, 3));
        JTextField npcField = new JTextField((String) roomModel.getValueAt(selectedRow, 4));

        panel.add(new JLabel("名称:"));
        panel.add(nameField);
        panel.add(new JLabel("尺寸:"));
        panel.add(sizeField);
        panel.add(new JLabel("界面固定:"));
        panel.add(movableCombo);
        panel.add(new JLabel("传送点:"));
        panel.add(wayPointField);
        panel.add(new JLabel("关联NPC:"));
        panel.add(npcField);

        int result = JOptionPane.showConfirmDialog(this, panel, "编辑房间", JOptionPane.OK_CANCEL_OPTION);
        if (result == JOptionPane.OK_OPTION) {
            String name = nameField.getText().trim();
            String size = sizeField.getText().trim();
            Boolean movable = (Boolean) movableCombo.getSelectedItem();
            String wayPoints = wayPointField.getText().trim();
            String npcs = npcField.getText().trim();

            if (!name.isEmpty() && !size.isEmpty() && movable != null && !wayPoints.isEmpty() && !npcs.isEmpty()) {
                if (!isValidCoordinate(size)) {
                    showError("尺寸格式错误");
                    return;
                }
                roomModel.setValueAt(name, selectedRow, 0);
                roomModel.setValueAt(size, selectedRow, 1);
                roomModel.setValueAt(movable, selectedRow, 2);
                roomModel.setValueAt(wayPoints, selectedRow, 3);
                roomModel.setValueAt(npcs, selectedRow, 4);
            } else {
                showError("请填写所有信息");
            }
        }
    }

    private void editWayPointRow(int selectedRow) {
        JPanel panel = new JPanel(new GridLayout(0, 2));
        JTextField typeField = new JTextField((String) wayPointModel.getValueAt(selectedRow, 0));
        JTextField apertureField = new JTextField((String) wayPointModel.getValueAt(selectedRow, 1));
        JTextField startField = new JTextField();
        JTextField startNoteField = new JTextField();
        JTextField endField = new JTextField();
        JTextField endNoteField = new JTextField();
        JTextField roomField = new JTextField((String) wayPointModel.getValueAt(selectedRow, 4));

        String[] startParts = ((String) wayPointModel.getValueAt(selectedRow, 2)).split(" ");
        String[] endParts = ((String) wayPointModel.getValueAt(selectedRow, 3)).split(" ");

        startField.setText(startParts[0]);
        startNoteField.setText(startParts.length > 1 ?
                startParts[1].replace("(", "").replace(")", "") : "");
        endField.setText(endParts[0]);
        endNoteField.setText(endParts.length > 1 ?
                endParts[1].replace("(", "").replace(")", "") : "");

        panel.add(new JLabel("类型:"));
        panel.add(typeField);
        panel.add(new JLabel("光圈坐标(x,y):"));
        panel.add(apertureField);
        panel.add(new JLabel("起始坐标(x,y):"));
        panel.add(startField);
        panel.add(new JLabel("起始备注:"));
        panel.add(startNoteField);
        panel.add(new JLabel("终点坐标(x,y):"));
        panel.add(endField);
        panel.add(new JLabel("终点备注:"));
        panel.add(endNoteField);
        panel.add(new JLabel("所属房间:"));
        panel.add(roomField);

        int result = JOptionPane.showConfirmDialog(this, panel, "编辑传送点", JOptionPane.OK_CANCEL_OPTION);
        if (result == JOptionPane.OK_OPTION) {
            String aperture = apertureField.getText().trim();
            String start = startField.getText().trim();
            String end = endField.getText().trim();

            if (isValidCoordinate(aperture) && isValidCoordinate(start) && isValidCoordinate(end)) {
                String combinedStart = start + " (" + startNoteField.getText().trim() + ")";
                String combinedEnd = end + " (" + endNoteField.getText().trim() + ")";

                wayPointModel.setValueAt(typeField.getText(), selectedRow, 0);
                wayPointModel.setValueAt(aperture, selectedRow, 1);
                wayPointModel.setValueAt(combinedStart, selectedRow, 2);
                wayPointModel.setValueAt(combinedEnd, selectedRow, 3);
                wayPointModel.setValueAt(roomField.getText(), selectedRow, 4);
            } else {
                showError("坐标格式无效");
            }
        }
    }

    private JTable createSceneTable() {
        sceneModel = new DefaultTableModel(new Object[][]{}, new String[]{"属性", "值"}) {
            @Override public boolean isCellEditable(int row, int column) { return column == 1; }
        };
        JTable table = new JTable(sceneModel);
        styleTable(table);
        return table;
    }

    private JTable createNpcTable() {
        npcModel = new DefaultTableModel(new Object[][]{},
                new String[]{"名称", "类型", "坐标", "对话内容"}) {
            @Override public boolean isCellEditable(int row, int column) { return column == 2; }
        };
        JTable table = new JTable(npcModel);
        styleTable(table);
        table.getColumnModel().getColumn(0).setPreferredWidth(250);
        table.getColumnModel().getColumn(1).setPreferredWidth(150);
        table.getColumnModel().getColumn(2).setPreferredWidth(300);
        table.getColumnModel().getColumn(3).setPreferredWidth(400);
        table.getColumnModel().getColumn(2).setCellEditor(new CoordinateComboBoxEditor());
        return table;
    }

    private class CoordinateComboBoxEditor extends DefaultCellEditor {
        private JComboBox<String> comboBox;
        private int currentRow;
        private List<String> allCoordinates;
        private String originalSelection; // 记录编辑前的选择

        public CoordinateComboBoxEditor() {
            super(new JComboBox<>());
            comboBox = (JComboBox<String>) getComponent();
            comboBox.setEditable(true);
            comboBox.addActionListener(e -> updateTableData());

            // 添加焦点监听确保直接输入也能触发保存
            comboBox.getEditor().getEditorComponent().addFocusListener(new FocusAdapter() {
                @Override
                public void focusLost(FocusEvent e) {
                    stopCellEditing();
                }
            });
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value,
                                                     boolean isSelected, int row, int column) {
            currentRow = row;
            String currentValue = (String) npcModel.getValueAt(row, 2);
            allCoordinates = new ArrayList<>(Arrays.asList(currentValue.split(" ")));
            originalSelection = (String) comboBox.getSelectedItem(); // 记录初始选择

            refreshComboBoxItems();
            SwingUtilities.invokeLater(() -> {
                comboBox.getEditor().selectAll();
                comboBox.showPopup();
            });
            return comboBox;
        }

        private void refreshComboBoxItems() {
            comboBox.removeAllItems();
            allCoordinates.forEach(comboBox::addItem);

            // 恢复编辑前的选择状态
            if (originalSelection != null) {
                comboBox.setSelectedItem(originalSelection);
            } else if (!allCoordinates.isEmpty()) {
                comboBox.setSelectedIndex(0);
            }
        }

        private void updateTableData() {
            if (currentRow == -1) return;

            String newValue = comboBox.getEditor().getItem().toString().trim();
            List<String> currentCoordinates = new ArrayList<>(allCoordinates);

            // 处理直接输入新坐标的情况
            if (!newValue.isEmpty() && isValidCoordinate(newValue)) {
                if (comboBox.getSelectedItem() != null) {
                    // 修改现有坐标
                    int index = currentCoordinates.indexOf(comboBox.getSelectedItem().toString());
                    if (index != -1) {
                        currentCoordinates.set(index, newValue);
                    }
                } else if (!currentCoordinates.contains(newValue)) {
                    // 新增坐标
                    currentCoordinates.add(newValue);
                }
            }

            // 自动去重并保持原始顺序
            currentCoordinates = currentCoordinates.stream()
                    .distinct()
                    .collect(Collectors.toList());

            // 更新单元格数据
            String updatedCoordinates = String.join(" ", currentCoordinates);
            npcModel.setValueAt(updatedCoordinates, currentRow, 2);

            // 强制刷新渲染
            SwingUtilities.invokeLater(() -> {
                npcTable.repaint();
                npcTable.changeSelection(currentRow, 2, false, false);
            });
        }

        @Override
        public boolean stopCellEditing() {
            updateTableData();
            return super.stopCellEditing();
        }

        @Override
        public Object getCellEditorValue() {
            return comboBox.getSelectedItem() != null ?
                    comboBox.getSelectedItem() :
                    comboBox.getEditor().getItem();
        }
    }

    private JTable createRoomTable() {
        roomModel = new DefaultTableModel(new Object[][]{},
                new String[]{"名称", "尺寸", "界面固定", "传送点", "关联NPC"}) {
            @Override public Class<?> getColumnClass(int column) {
                return column == 2 ? Boolean.class : String.class;
            }
            @Override public boolean isCellEditable(int row, int column) { return column == 3; }
        };
        JTable table = new JTable(roomModel);
        styleTable(table);
        table.getColumnModel().getColumn(0).setPreferredWidth(80);
        table.getColumnModel().getColumn(1).setPreferredWidth(80);
        table.getColumnModel().getColumn(2).setPreferredWidth(100);
        table.getColumnModel().getColumn(3).setPreferredWidth(100);
        table.getColumnModel().getColumn(4).setPreferredWidth(150);
        JComboBox<String> wayPointComboBox = new JComboBox<>(Arrays.asList("传送点1", "传送点2", "传送点3").toArray(new String[0]));
        table.getColumnModel().getColumn(3).setCellEditor(new DefaultCellEditor(wayPointComboBox));
        return table;
    }

    private JTable createWayPointTable() {
        wayPointModel = new DefaultTableModel(new Object[][]{},
                new String[]{"类型", "光圈坐标", "起始坐标(备注)", "终点坐标(备注)", "所属房间"});
        JTable table = new JTable(wayPointModel);
        styleTable(table); // 添加样式应用
        table.getColumnModel().getColumn(0).setPreferredWidth(100);
        table.getColumnModel().getColumn(1).setPreferredWidth(150);
        table.getColumnModel().getColumn(2).setPreferredWidth(260);
        table.getColumnModel().getColumn(3).setPreferredWidth(260);
        table.getColumnModel().getColumn(4).setPreferredWidth(150);
        return table;
    }

    private JToolBar createToolBar() {
        JToolBar toolBar = new JToolBar();
        toolBar.setFloatable(false);
        toolBar.setBorder(new EmptyBorder(0, 20, 0, 0));

        openBtn = createStyledButton("打开");
        toolBar.add(openBtn);
        toolBar.add(Box.createHorizontalStrut(20));

        saveBtn = createStyledButton("保存");
        toolBar.add(saveBtn);
        toolBar.add(Box.createHorizontalStrut(20));

        saveAsBtn = createStyledButton("另存为");
        toolBar.add(saveAsBtn);
        toolBar.add(Box.createHorizontalStrut(20));

        newSceneBtn = createStyledButton("新建场景");
        toolBar.add(newSceneBtn);
        toolBar.add(Box.createHorizontalStrut(20));

        helpBtn = createStyledButton("帮助");
        toolBar.add(helpBtn);
        toolBar.add(Box.createHorizontalStrut(20));

        addNpcBtn = createStyledButton("加NPC");
        toolBar.add(addNpcBtn);
        toolBar.add(Box.createHorizontalStrut(20));

        addWayPointBtn = createStyledButton("加传送点");
        toolBar.add(addWayPointBtn);
        toolBar.add(Box.createHorizontalStrut(20));

        addBtn = createStyledButton("加房间");
        toolBar.add(addBtn);

        return toolBar;
    }

    private JButton createStyledButton(String text) {
        JButton btn = new JButton(text);
        btn.setFont(LABEL_FONT.deriveFont(16f));
        btn.setFocusPainted(false);
        btn.setBackground(Color.WHITE);
        btn.setBorder(new CompoundBorder(
                new LineBorder(new Color(200, 200, 200)),
                new EmptyBorder(5, 15, 5, 15)
        ));
        btn.addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) { btn.setBackground(new Color(200, 200, 200)); }
            public void mouseExited(MouseEvent e) { btn.setBackground(Color.WHITE); }
        });
        return btn;
    }

    private JScrollPane createTablePanel(JTable table) {
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setBorder(new CompoundBorder(
                new EmptyBorder(10, 10, 10, 10),
                new LineBorder(new Color(200, 200, 200))
        ));
        return scrollPane;
    }

    private void styleTable(JTable table) {
        table.setRowHeight((int) (30 * SCALE_FACTOR));
        table.setFont(LABEL_FONT.deriveFont(26f));
        table.getTableHeader().setFont(TITLE_FONT.deriveFont(28f));
        table.setShowGrid(false);
        table.setIntercellSpacing(new Dimension(0, 3));
        table.setSelectionBackground(new Color(255, 0, 0));
        table.setSelectionForeground(Color.WHITE);

        // 通用渲染器设置
        DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
        centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);

        for (int i = 0; i < table.getColumnCount(); i++) {
            table.getColumnModel().getColumn(i).setCellRenderer(centerRenderer);
        }
    }

    private void setupTableRenderers() {
        // 创建通用居中渲染器
        DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                                                           boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

                // 动态行高计算（基于内容）
                if (table == npcTable && column == 3 && value != null) {
                    int lineCount = ((String) value).split("\n").length;
                    int requiredHeight = Math.min(lineCount, 5) * MultiLineCellRenderer.LINE_HEIGHT + 10;
                    if (table.getRowHeight(row) < requiredHeight) {
                        table.setRowHeight(row, requiredHeight);
                    }
                }

                return c;
            }
        };
        centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);

        // NPC对话内容专用渲染器（支持多行显示，限制行数）
        DefaultTableCellRenderer dialogueRenderer = new DefaultTableCellRenderer() {
            private final MultiLineCellRenderer textRenderer = new MultiLineCellRenderer();

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                                                           boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                JComponent comp = (JComponent) textRenderer.getTableCellRendererComponent(
                        table, value, isSelected, hasFocus, row, column
                );

                return comp;
            }
        };

        // 场景属性表格样式
        sceneTable.setDefaultRenderer(Object.class, centerRenderer);
        sceneTable.getColumnModel().getColumn(0).setPreferredWidth(150);
        sceneTable.getColumnModel().getColumn(1).setPreferredWidth(350);

        // NPC管理表格样式配置
        npcTable.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                                                           boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

                // 统一字体样式
                c.setFont(LABEL_FONT.deriveFont(26f));

                // 交替行颜色
                if (!isSelected) {
                    c.setBackground(row % 2 == 0 ? Color.WHITE : new Color(245, 245, 245));
                }

                return c;
            }
        });

        // 应用专用渲染器到对话内容列（索引3）
        npcTable.getColumnModel().getColumn(3).setCellRenderer(dialogueRenderer);

        // 前三列居中对齐
        for (int i = 0; i < 3; i++) {
            npcTable.getColumnModel().getColumn(i).setCellRenderer(centerRenderer);
        }

        // 房间管理表格样式
        roomTable.setDefaultRenderer(Object.class, centerRenderer);
        roomTable.getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                                                           boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                // 布尔值特殊显示
                String text = (Boolean.TRUE.equals(value)) ? "是" : "否";
                return super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);
            }
        });

        // 传送点管理表格样式
        wayPointTable.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                                                           boolean isSelected, boolean hasFocus,
                                                           int row, int column) {
                Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

                // 基础样式设置
                c.setFont(LABEL_FONT.deriveFont(26f));
                ((JLabel) c).setHorizontalAlignment(SwingConstants.CENTER);

                // 交替行颜色
                if (!isSelected) {
                    c.setBackground(row % 2 == 0 ? Color.WHITE : new Color(240, 240, 240));
                }

                // 特殊列样式（类型列）
                if (column == 0 && value != null) {
                    String type = value.toString();
                    switch (type) {
                        case "入口":
                            c.setForeground(new Color(0, 100, 0));
                            break;
                        case "出口":
                            c.setForeground(new Color(150, 0, 0));
                            break;
                        default:
                            c.setForeground(Color.BLACK);
                    }
                }

                return c;
            }
        });

        // 统一表格样式配置
        for (JTable table : Arrays.asList(sceneTable, npcTable, roomTable, wayPointTable)) {
            table.setRowHeight(30 * (int)SCALE_FACTOR);
            table.setFont(LABEL_FONT.deriveFont(26f));
            table.getTableHeader().setFont(TITLE_FONT.deriveFont(28f));
            table.setShowGrid(false);
            table.setIntercellSpacing(new Dimension(0, 3));
            table.setSelectionBackground(new Color(255, 0, 0));
            table.setSelectionForeground(Color.WHITE);
        }
    }

    private class MultiLineCellRenderer extends JTextArea implements TableCellRenderer {
        private static final int MAX_LINES = 5;
        private static final int LINE_HEIGHT = 24;
        private static final int MAX_HEIGHT = MAX_LINES * LINE_HEIGHT;

        public MultiLineCellRenderer() {
            setLineWrap(true);
            setWrapStyleWord(true);
            setEditable(false);
            setFont(LABEL_FONT.deriveFont(26f));
            setOpaque(true); // 确保背景色可以显示
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                                                       boolean isSelected, boolean hasFocus,
                                                       int row, int column) {
            String rawText = (value != null) ? value.toString() : "";
            setText(rawText);

            // 限制显示的行数
            if (getLineCount() > MAX_LINES) {
                // 截取前 MAX_LINES 行
                try {
                    int endIndex = getLineEndOffset(MAX_LINES - 1);
                    String truncatedText = getText(0, endIndex).trim();
                    // 添加省略号表示有更多内容
                    if (!truncatedText.endsWith("...")) {
                        truncatedText = truncatedText + "...";
                    }
                    setText(truncatedText);
                } catch (Exception e) {
                    // 异常处理
                    setText(rawText);
                }
            }

            // 设置固定高度
            setPreferredSize(new Dimension(getPreferredSize().width, MAX_HEIGHT));

            // 样式配置
            setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
            setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());

            return this;
        }
    }

    public void addOpenButtonListener(ActionListener listener) {
        openBtn.addActionListener(listener);
    }

    public void addSaveButtonListener(ActionListener listener) {
        saveBtn.addActionListener(listener);
    }

    public void addSaveAsButtonListener(ActionListener listener) {
        saveAsBtn.addActionListener(listener);
    }

    public void addHelpButtonListener(ActionListener listener) {
        helpBtn.addActionListener(listener);
    }

    public void addAddWayPointButtonListener(ActionListener listener) {
        addWayPointBtn.addActionListener(listener);
    }

    public void refreshSceneTable(Scene scene) {
        sceneModel.setRowCount(0);
        if (scene != null) {
            sceneModel.addRow(new Object[]{"名称", scene.getName()});
            /** 增加一个数据 */
            sceneModel.addRow(new Object[]{"Tab键打开所在位置", scene.getName()});
            sceneModel.addRow(new Object[]{"大小", formatCoordinate(scene.getSize())});
            sceneModel.addRow(new Object[]{"是否遇怪", scene.isEncounters() ? "是" : "否"});
        }
    }

    public void refreshNpcTable(List<INpc> npcs) {
        npcModel.setRowCount(0);
        if (npcs != null) {
            for (INpc npc : npcs) {
                String type = "普通NPC";
                if (npc instanceof MerchantNpc) type = "商人";
                else if (npc instanceof TransferNpc) type = "传送NPC";

                NPC concrete = (NPC) npc;
                StringBuilder dialogueBuilder = new StringBuilder();
                for (Map.Entry<String, List<String>> entry : concrete.getDialogues().entrySet()) {
                    // 保持原始数据格式（不带前缀）
                    dialogueBuilder.append(entry.getKey())
                            .append(": ")
                            .append(String.join(", ", entry.getValue()))
                            .append("\n");
                }

                npcModel.addRow(new Object[]{
                        concrete.getName(),
                        type,
                        formatCoordinates(concrete.getLocations()),
                        dialogueBuilder.toString().trim() // 保持原始数据
                });
            }
        }
    }

    public void refreshRoomTable(List<Room> rooms) {
        roomModel.setRowCount(0);
        for (Room room : rooms) {
            String wayPointsInfo = room.getWayPoints().stream()
                    .map(wp -> wp.getType() + "(" + wp.getAperture().getX() + "," + wp.getAperture().getY() + ")")
                    .collect(Collectors.joining(", "));

            roomModel.addRow(new Object[]{
                    room.getName(),
                    formatCoordinate(room.getSize()),
                    room.isMovable(),
                    wayPointsInfo,
                    getNpcNames(room)
            });
        }
    }

    public void refreshWayPointTable(List<WayPoint> wayPoints) {
        wayPointModel.setRowCount(0);
        for (WayPoint wp : wayPoints) {
            wayPointModel.addRow(new Object[]{
                    wp.getType(),
                    formatCoordinate(wp.getAperture()),
                    formatCoordinate(wp.getStartPoint()),
                    formatCoordinate(wp.getClockPoint())
            });
        }
    }

    private String formatCoordinate(Coordinate coord) {
        return coord != null ? coord.getX() + ", " + coord.getY() : "无";
    }

    private String formatCoordinates(List<Coordinate> coords) {
        if (coords == null || coords.isEmpty()) return "无";
        StringBuilder sb = new StringBuilder();
        for (Coordinate c : coords) {
            sb.append(c.getX()).append(",").append(c.getY()).append(" ");
        }
        return sb.toString().trim();
    }

    private String getNpcNames(Room room) {
        if (room.getNpcs() == null) return "无";
        return room.getNpcs().stream()
                .map(npc -> ((NPC) npc).getName())
                .collect(Collectors.joining(", "));
    }

    public void showStatus(String message) {
        statusLabel.setText(message);
        statusLabel.setForeground(new Color(60, 60, 60));
    }

    public void showError(String message) {
        statusLabel.setText(message);
        statusLabel.setForeground(Color.RED);
        JOptionPane.showMessageDialog(this, message, "错误", JOptionPane.ERROR_MESSAGE);
    }

    public void showHelp() {
        JOptionPane.showMessageDialog(this,
                "场景编辑器使用指南：\n"
                        + "1. 使用工具栏按钮打开/保存XML文件\n"
                        + "2. 通过标签页管理不同数据\n"
                        + "3. 双击表格行进行详细编辑\n"
                        + "4. 右键点击表格使用上下文菜单",
                "帮助信息",
                JOptionPane.INFORMATION_MESSAGE);
    }

    private void showOpen() {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setFileFilter(new FileNameExtensionFilter("XML Files", "xml"));

        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            parseAndPopulateTables(selectedFile);
        }
    }

    private void showSave(){
        if (currentFile != null) {
            // 保存到当前文件
            saveToFile(currentFile);
        } else {
            // 没有选择文件，调用另存为方法
            showLin();
        }
    }

    private void showLin(){
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setFileFilter(new FileNameExtensionFilter("XML Files", "xml"));
        fileChooser.setDialogTitle("另存为");

        int result = fileChooser.showSaveDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            // 确保文件扩展名是 .xml
            if (!selectedFile.getName().toLowerCase().endsWith(".xml")) {
                selectedFile = new File(selectedFile.getParentFile(), selectedFile.getName() + ".xml");
            }
            currentFile = selectedFile;
            saveToFile(selectedFile);
        }
    }

    private String parseDialoguesElement(Element parent, String tagName) {
        NodeList nodeList = parent.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0) {
            Element dialoguesElement = (Element) nodeList.item(0);
            NodeList dialogueNodes = dialoguesElement.getElementsByTagName("dialogue");
            List<String> dialogues = new ArrayList<>();

            for (int i = 0; i < dialogueNodes.getLength(); i++) {
                dialogues.add(dialogueNodes.item(i).getTextContent().trim());
            }

            return String.join("\n", dialogues);
        }
        return "";
    }

    private String parseCoordinateElement(Element parent, String tagName) {
        NodeList nodeList = parent.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0) {
            Element coordElement = (Element) nodeList.item(0);
            String x = getElementText(coordElement, "x");
            String y = getElementText(coordElement, "y");
            return x + ", " + y;
        }
        return "";
    }

    private String parseCoordinatesElement(Element parent, String tagName) {
        NodeList nodeList = parent.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0) {
            Element locationsElement = (Element) nodeList.item(0);
            NodeList coordinateNodes = locationsElement.getElementsByTagName("Coordinate");
            List<String> coordinates = new ArrayList<>();

            for (int i = 0; i < coordinateNodes.getLength(); i++) {
                Element coordElement = (Element) coordinateNodes.item(i);
                String x = getElementText(coordElement, "x");
                String y = getElementText(coordElement, "y");
                coordinates.add(x + "," + y);
            }

            return String.join(" ", coordinates);
        }
        return "";
    }

    private void parseWayPointData(Document doc) {
        wayPointModel.setRowCount(0);
        NodeList wayPointNodes = doc.getElementsByTagName("WayPoint");

        for (int i = 0; i < wayPointNodes.getLength(); i++) {
            Node wayPointNode = wayPointNodes.item(i);
            if (wayPointNode.getNodeType() == Node.ELEMENT_NODE) {
                Element wayPointElement = (Element) wayPointNode;

                String type = getElementText(wayPointElement, "type");
                String aperture = parseCoordinateElement(wayPointElement, "aperture");
                String startPoint = parseCoordinateElement(wayPointElement, "startPoint");
                String startNote = getElementText(wayPointElement, "startNote");
                String clockPoint = parseCoordinateElement(wayPointElement, "clockPoint");
                String endNote = getElementText(wayPointElement, "endNote");
                String room = getElementText(wayPointElement, "room");

                String combinedStart = startPoint + " (" + startNote + ")";
                String combinedEnd = clockPoint + " (" + endNote + ")";

                wayPointModel.addRow(new Object[]{type, aperture, combinedStart, combinedEnd, room});
            }
        }
    }

    private void parseRoomData(Document doc) {
        roomModel.setRowCount(0);
        NodeList roomNodes = doc.getElementsByTagName("Room");

        for (int i = 0; i < roomNodes.getLength(); i++) {
            Node roomNode = roomNodes.item(i);
            if (roomNode.getNodeType() == Node.ELEMENT_NODE) {
                Element roomElement = (Element) roomNode;

                String name = getElementText(roomElement, "name");
                String size = parseCoordinateElement(roomElement, "Size");
                boolean movable = Boolean.parseBoolean(getElementText(roomElement, "movable"));
                String wayPoints = getElementText(roomElement, "wayPoints");
                String npcs = getElementText(roomElement, "npcs");

                roomModel.addRow(new Object[]{name, size, movable, wayPoints, npcs});
            }
        }
    }

    private void parseNpcData(Document doc) {
        npcModel.setRowCount(0);
        NodeList npcNodes = doc.getElementsByTagName("Npc");

        for (int i = 0; i < npcNodes.getLength(); i++) {
            Node npcNode = npcNodes.item(i);
            if (npcNode.getNodeType() == Node.ELEMENT_NODE) {
                Element npcElement = (Element) npcNode;

                String name = getElementText(npcElement, "name");
                String type = getElementText(npcElement, "type");
                String coordinates = parseCoordinatesElement(npcElement, "locations");
                String dialogues = parseDialoguesElement(npcElement, "dialogues");

                npcModel.addRow(new Object[]{name, type, coordinates, dialogues});
            }
        }
    }

    private void parseSceneProperties(Document doc) {
    sceneModel.setRowCount(0);
    Element root = doc.getDocumentElement();

    String name = getElementText(root, "name");
    String tabOpenLocation = getElementText(root, "tabOpenLocation");
    String size = parseCoordinateElement(root, "Size");
    String encounters = getElementText(root, "encounters");

    sceneModel.addRow(new Object[]{"名称", name});
    sceneModel.addRow(new Object[]{"Tab键打开所在位置", tabOpenLocation});
    sceneModel.addRow(new Object[]{"大小", size});
    sceneModel.addRow(new Object[]{"是否遇怪", encounters});
}

    private void parseAndPopulateTables(File xmlFile) {
        try {
            // 创建 DocumentBuilderFactory 和 DocumentBuilder
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(xmlFile);

            // 规范化文档
            doc.getDocumentElement().normalize();

            // 解析场景属性
            parseSceneProperties(doc);

            // 解析 NPC 数据
            parseNpcData(doc);

            // 解析房间数据
            parseRoomData(doc);

            // 解析传送点数据
            parseWayPointData(doc);

            showStatus("文件加载成功: " + xmlFile.getName());
        } catch (Exception e) {
            showError("文件解析失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private String getElementText(Element parent, String tagName) {
        NodeList nodeList = parent.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0) {
            return nodeList.item(0).getTextContent().trim();
        }
        return "";
    }

    private void saveToFile(File file) {
        try {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            // 创建根节点
            Document doc = docBuilder.newDocument();
            Element rootElement = doc.createElement("root");
            doc.appendChild(rootElement);

            // 保存场景属性
            saveSceneToXml(doc, rootElement);

            // 保存 NPC 数据
            saveNpcsToXml(doc, rootElement);

            // 保存房间数据
            saveRoomsToXml(doc, rootElement);

            // 保存传送点数据
            saveWayPointsToXml(doc, rootElement);

            // 将文档写入文件
            javax.xml.transform.TransformerFactory transformerFactory = javax.xml.transform.TransformerFactory.newInstance();
            javax.xml.transform.Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes");
            javax.xml.transform.dom.DOMSource source = new javax.xml.transform.dom.DOMSource(doc);
            javax.xml.transform.stream.StreamResult result = new javax.xml.transform.stream.StreamResult(file);
            transformer.transform(source, result);

            showStatus("文件保存成功: " + file.getName());
        } catch (javax.xml.parsers.ParserConfigurationException e) {
            showError("XML 解析器配置错误: " + e.getMessage());
            e.printStackTrace();
        } catch (javax.xml.transform.TransformerException e) {
            showError("XML 转换错误: " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            showError("文件保存失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private void saveSceneToXml(Document doc, Element rootElement) {
        if (sceneModel.getRowCount() >= 4) {
            // 保存场景名称
            Element nameElement = doc.createElement("name");
            nameElement.setTextContent((String) sceneModel.getValueAt(0, 1));
            rootElement.appendChild(nameElement);

            // 保存 TAB 打开的位置
            Element tabOpenLocationElement = doc.createElement("tabOpenLocation");
            tabOpenLocationElement.setTextContent((String) sceneModel.getValueAt(1, 1));
            rootElement.appendChild(tabOpenLocationElement);

            // 保存场景大小
            Element sizeElement = doc.createElement("Size");
            try {
                String[] sizeParts = ((String) sceneModel.getValueAt(2, 1)).split(",");
                Element xElement = doc.createElement("x");
                xElement.setTextContent(sizeParts[0].trim());
                sizeElement.appendChild(xElement);
                Element yElement = doc.createElement("y");
                yElement.setTextContent(sizeParts[1].trim());
                sizeElement.appendChild(yElement);
                rootElement.appendChild(sizeElement);
            } catch (Exception e) {
                showError("场景大小数据格式错误: " + e.getMessage());
            }

            // 保存是否遇怪
            Element encountersElement = doc.createElement("encounters");
            encountersElement.setTextContent((String) sceneModel.getValueAt(3, 1));
            rootElement.appendChild(encountersElement);
        } else {
            showError("场景数据不完整，无法保存");
        }
    }

    private void saveNpcsToXml(Document doc, Element rootElement) {
        Element npcsElement = doc.createElement("npcs");
        rootElement.appendChild(npcsElement);

        System.out.println("开始保存 NPC 数据，行数: " + npcModel.getRowCount());

        for (int i = 0; i < npcModel.getRowCount(); i++) {
            try {
                String name = (String) npcModel.getValueAt(i, 0);
                String type = (String) npcModel.getValueAt(i, 1);
                String coordinates = (String) npcModel.getValueAt(i, 2);
                String dialogues = (String) npcModel.getValueAt(i, 3);

                System.out.println("正在保存第 " + (i + 1) + " 行 NPC 数据: 名称=" + name + ", 类型=" + type);

                Element npcElement;
                switch (type) {
                    case "商人":
                        npcElement = doc.createElement("MerchantNpc");
                        Element merchantNameElement = doc.createElement("merchantName");
                        merchantNameElement.setTextContent(name);
                        npcElement.appendChild(merchantNameElement);
                        break;
                    case "传送NPC":
                        npcElement = doc.createElement("TransferNpc");
                        Element transferNameElement = doc.createElement("TransferName");
                        transferNameElement.setTextContent(name);
                        npcElement.appendChild(transferNameElement);
                        break;
                    default:
                        npcElement = doc.createElement("Npc");
                        break;
                }

                // 保存 NPC 名字
                Element nameNode = doc.createElement("name");
                nameNode.setTextContent(name);
                npcElement.appendChild(nameNode);

                // 保存 NPC 类型
                Element typeNode = doc.createElement("type");
                typeNode.setTextContent(type);
                npcElement.appendChild(typeNode);

                // 保存坐标
                Element locationsElement = doc.createElement("locations");
                if (!coordinates.isEmpty()) {
                    String[] coordArray = coordinates.split(" ");
                    for (String coord : coordArray) {
                        if (coord.contains(",")) {
                            String[] parts = coord.split(",");
                            if (parts.length == 2) {
                                Element coordinateElement = doc.createElement("Coordinate");
                                Element xElement = doc.createElement("x");
                                xElement.setTextContent(parts[0].trim());
                                coordinateElement.appendChild(xElement);
                                Element yElement = doc.createElement("y");
                                yElement.setTextContent(parts[1].trim());
                                coordinateElement.appendChild(yElement);
                                locationsElement.appendChild(coordinateElement);
                            } else {
                                System.out.println("第 " + (i + 1) + " 行 NPC 坐标格式错误: " + coord);
                            }
                        }
                    }
                }
                npcElement.appendChild(locationsElement);

                // 保存对话，将对话内容按行分割后逐个保存
                Element dialoguesElement = doc.createElement("dialogues");
                if (!dialogues.isEmpty()) {
                    String[] dialogueLines = dialogues.split("\n");
                    for (String line : dialogueLines) {
                        Element dialogueElement = doc.createElement("dialogue");
                        dialogueElement.setTextContent(line.trim());
                        dialoguesElement.appendChild(dialogueElement);
                    }
                }
                npcElement.appendChild(dialoguesElement);

                npcsElement.appendChild(npcElement);
            } catch (Exception e) {
                System.out.println("保存第 " + (i + 1) + " 行 NPC 数据时出错: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }
    private void saveRoomsToXml(Document doc, Element rootElement) {
        Element roomsElement = doc.createElement("rooms");
        rootElement.appendChild(roomsElement);

        System.out.println("开始保存房间数据，行数: " + roomModel.getRowCount());

        for (int i = 0; i < roomModel.getRowCount(); i++) {
            try {
                Element roomElement = doc.createElement("Room");

                // 保存房间名称
                String roomName = (String) roomModel.getValueAt(i, 0);
                Element nameElement = doc.createElement("name");
                nameElement.setTextContent(roomName);
                roomElement.appendChild(nameElement);

                // 保存房间尺寸
                String sizeStr = (String) roomModel.getValueAt(i, 1);
                Element sizeElement = doc.createElement("Size");
                String[] sizeParts = sizeStr.split(",");
                if (sizeParts.length == 2) {
                    Element xElement = doc.createElement("x");
                    xElement.setTextContent(sizeParts[0].trim());
                    sizeElement.appendChild(xElement);
                    Element yElement = doc.createElement("y");
                    yElement.setTextContent(sizeParts[1].trim());
                    sizeElement.appendChild(yElement);
                } else {
                    System.out.println("第 " + (i + 1) + " 行房间尺寸格式错误: " + sizeStr);
                }
                roomElement.appendChild(sizeElement);

                // 保存界面固定状态
                Boolean movable = (Boolean) roomModel.getValueAt(i, 2);
                Element movableElement = doc.createElement("movable");
                movableElement.setTextContent(movable.toString());
                roomElement.appendChild(movableElement);

                // 保存传送点，直接保存为字符串
                String wayPointsStr = (String) roomModel.getValueAt(i, 3);
                Element wayPointsElement = doc.createElement("wayPoints");
                wayPointsElement.setTextContent(wayPointsStr);
                roomElement.appendChild(wayPointsElement);

                // 保存关联 NPC
                String npcsStr = (String) roomModel.getValueAt(i, 4);
                Element npcsElement = doc.createElement("npcs");
                npcsElement.setTextContent(npcsStr);
                roomElement.appendChild(npcsElement);

                roomsElement.appendChild(roomElement);
            } catch (Exception e) {
                System.out.println("保存第 " + (i + 1) + " 行房间数据时出错: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    private void saveWayPointsToXml(Document doc, Element rootElement) {
        Element wayPointsElement = doc.createElement("wayPoints");
        rootElement.appendChild(wayPointsElement);

        for (int i = 0; i < wayPointModel.getRowCount(); i++) {
            Element wayPointElement = doc.createElement("WayPoint");

            // 保存传送点类型
            Element typeElement = doc.createElement("type");
            typeElement.setTextContent((String) wayPointModel.getValueAt(i, 0));
            wayPointElement.appendChild(typeElement);

            // 保存光圈坐标
            Element apertureElement = doc.createElement("aperture");
            String[] apertureParts = ((String) wayPointModel.getValueAt(i, 1)).split(",");
            Element xElement = doc.createElement("x");
            xElement.setTextContent(apertureParts[0].trim());
            apertureElement.appendChild(xElement);
            Element yElement = doc.createElement("y");
            yElement.setTextContent(apertureParts[1].trim());
            apertureElement.appendChild(yElement);
            wayPointElement.appendChild(apertureElement);

            // 保存起始坐标和备注
            String startStr = (String) wayPointModel.getValueAt(i, 2);
            int startIndex = startStr.indexOf("(");
            String startCoord = startStr.substring(0, startIndex).trim();
            String startNote = startStr.substring(startIndex + 1, startStr.length() - 1).trim();
            String[] startParts = startCoord.split(",");

            Element startPointElement = doc.createElement("startPoint");
            Element startXElement = doc.createElement("x");
            startXElement.setTextContent(startParts[0].trim());
            startPointElement.appendChild(startXElement);
            Element startYElement = doc.createElement("y");
            startYElement.setTextContent(startParts[1].trim());
            startPointElement.appendChild(startYElement);
            wayPointElement.appendChild(startPointElement);

            Element startNoteElement = doc.createElement("startNote");
            startNoteElement.setTextContent(startNote);
            wayPointElement.appendChild(startNoteElement);

            // 保存终点坐标和备注
            String endStr = (String) wayPointModel.getValueAt(i, 3);
            int endIndex = endStr.indexOf("(");
            String endCoord = endStr.substring(0, endIndex).trim();
            String endNote = endStr.substring(endIndex + 1, endStr.length() - 1).trim();
            String[] endParts = endCoord.split(",");

            Element clockPointElement = doc.createElement("clockPoint");
            Element endXElement = doc.createElement("x");
            endXElement.setTextContent(endParts[0].trim());
            clockPointElement.appendChild(endXElement);
            Element endYElement = doc.createElement("y");
            endYElement.setTextContent(endParts[1].trim());
            clockPointElement.appendChild(endYElement);
            wayPointElement.appendChild(clockPointElement);

            Element endNoteElement = doc.createElement("endNote");
            endNoteElement.setTextContent(endNote);
            wayPointElement.appendChild(endNoteElement);

            // 保存所属房间
            Element roomElement = doc.createElement("room");
            roomElement.setTextContent((String) wayPointModel.getValueAt(i, 4));
            wayPointElement.appendChild(roomElement);

            wayPointsElement.appendChild(wayPointElement);
        }
    }

    private Scene parseScene(Element sceneElement) {
        Scene scene = new Scene();
        scene.setName(getTextContent(sceneElement, "name"));
        scene.setSize(parseCoordinate(sceneElement, "Size"));
        scene.setEncounters(Boolean.parseBoolean(getTextContent(sceneElement, "encounters")));
        return scene;
    }

    // 辅助解析方法
    private String getTextContent(Element element, String tagName) {
        return element.getElementsByTagName(tagName).item(0).getTextContent().trim();
    }

    private Coordinate parseCoordinate(Element parent, String tagName) {
        Element coordElement = (Element) parent.getElementsByTagName(tagName).item(0);
        return new Coordinate(
                Integer.parseInt(getTextContent(coordElement, "x")),
                Integer.parseInt(getTextContent(coordElement, "y"))
        );
    }

    // 新增辅助方法：解析坐标列表
    private List<Coordinate> parseCoordinates(Element parent, String tagName) {
        List<Coordinate> coordinates = new ArrayList<>();
        Element locationsElement = (Element) parent.getElementsByTagName(tagName).item(0);
        if (locationsElement != null) {
            NodeList coordinateNodes = locationsElement.getElementsByTagName("Coordinate");
            for (int i = 0; i < coordinateNodes.getLength(); i++) {
                Element coordElement = (Element) coordinateNodes.item(i);
                Coordinate coord = new Coordinate(
                        Integer.parseInt(getTextContent(coordElement, "x")),
                        Integer.parseInt(getTextContent(coordElement, "y"))
                );
                coordinates.add(coord);
            }
        }
        return coordinates;
    }

    // 新增辅助方法：解析对话
    private Map<String, List<String>> parseDialogues(Element parent) {
        Map<String, List<String>> dialogues = new HashMap<>();
        Element dialoguesElement = (Element) parent.getElementsByTagName("dialogues").item(0);
        if (dialoguesElement != null) {
            NodeList dialogueNodes = dialoguesElement.getElementsByTagName("dialogue");
            List<String> dialogueList = new ArrayList<>();
            for (int i = 0; i < dialogueNodes.getLength(); i++) {
                Element dialogueElement = (Element) dialogueNodes.item(i);
                dialogueList.add(dialogueElement.getTextContent().trim());
            }
            // 这里简单用一个固定的 key 来存储对话列表，你可以根据实际需求调整
            dialogues.put("default", dialogueList);
        }
        return dialogues;
    }

    // 新增辅助方法：解析房间内的传送点
    private List<WayPoint> parseWayPointsInRoom(Element roomElement) {
        List<WayPoint> wayPoints = new ArrayList<>();
        Element wayPointsElement = (Element) roomElement.getElementsByTagName("wayPoints").item(0);
        if (wayPointsElement != null) {
            String wayPointsStr = wayPointsElement.getTextContent();
            // 这里简单示例，实际可能需要根据具体格式解析
            // 假设格式还是 "类型1(坐标1), 类型2(坐标2)"
            String[] wayPointsArr = wayPointsStr.split(", ");
            for (String wpStr : wayPointsArr) {
                int index = wpStr.indexOf("(");
                if (index != -1) {
                    WayPoint wayPoint = new WayPoint();
                    wayPoint.setType(wpStr.substring(0, index));
                    String coordStr = wpStr.substring(index + 1, wpStr.length() - 1);
                    String[] coordParts = coordStr.split(",");
                    if (coordParts.length == 2) {
                        Coordinate aperture = new Coordinate(
                                Integer.parseInt(coordParts[0].trim()),
                                Integer.parseInt(coordParts[1].trim())
                        );
                        wayPoint.setAperture(aperture);
                    }
                    wayPoints.add(wayPoint);
                }
            }
        }
        return wayPoints;
    }

    // 新增辅助方法：解析房间内的 NPC
    private List<INpc> parseNpcsInRoom(Element roomElement) {
        List<INpc> npcs = new ArrayList<>();
        Element npcsElement = (Element) roomElement.getElementsByTagName("npcs").item(0);
        if (npcsElement != null) {
            NodeList merchantNpcNodes = npcsElement.getElementsByTagName("MerchantNpc");
            for (int i = 0; i < merchantNpcNodes.getLength(); i++) {
                Element npcElement = (Element) merchantNpcNodes.item(i);
                MerchantNpc merchantNpc = new MerchantNpc();
                merchantNpc.setMerchantName(getTextContent(npcElement, "merchantName"));
                merchantNpc.setName(getTextContent(npcElement, "name"));
                merchantNpc.setLocations(parseCoordinates(npcElement, "locations"));
                merchantNpc.setDialogues(parseDialogues(npcElement));
                npcs.add(merchantNpc);
            }
        }
        return npcs;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new SceneView());
    }
}